This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Project objective:

Use R and apply exploratory data analysis techniques to explore relationships in one variable to multiple variables and to explore a selected data set for distributions, outliers, and anomalies. I will be using a Udacity recommended data set.

Data:

I will use the suggested red wine data set which contains 1599 obervations of different red wines and their various chemical properties.

My approch:

I will use the red wine quality dataset to explore which features of wine can be indicative of it’s quality rating. The quality rating is an averega from a tasting panel.

Loading necessary libraries:

Error in install.packages : Updating loaded packages

Load in the datatset:

Variable description

  1. Fixed acidity: most acids involved with wine or fixed or nonvolatile (do not evaporate readily)
  2. Volatile acidity: the amount of acetic acid in wine, which at too high of levels can lead to an unpleasant, vinegar taste
  3. Citric acid: found in small quantities, citric acid can add ‘freshness’ and flavor to wines
  4. Residual sugar: the amount of sugar remaining after fermentation stops, it’s rare to find wines with less than 1 gram/liter and wines with greater than 45 grams/liter are considered sweet
  5. Chlorides: the amount of salt in the wine
  6. Free sulfur dioxide: the free form of SO2 exists in equilibrium between molecular SO2 (as a dissolved gas) and bisulfite ion; it prevents microbial growth and the oxidation of wine
  7. Total sulfur dioxide: amount of free and bound forms of S02; in low concentrations, SO2 is mostly undetectable in wine, but at free SO2 concentrations over 50 ppm, SO2 becomes evident in the nose and taste of wine
  8. Density: the density of water is close to that of water depending on the percent alcohol and sugar content
  9. pH: describes how acidic or basic a wine is on a scale from 0 (very acidic) to 14 (very basic); most wines are between 3-4 on the pH scale
  10. Sulphates: a wine additive which can contribute to sulfur dioxide gas (S02) levels, wich acts as an antimicrobial and antioxidant
  11. Alcohol: the percent alcohol content of the wine
  12. Quality: output variable (based on sensory data, score between 0 and 10)

Let’s get some preliminary summaries of the data:

[1] 1599   13
'data.frame':   1599 obs. of  13 variables:
 $ X                   : int  1 2 3 4 5 6 7 8 9 10 ...
 $ fixed.acidity       : num  7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 7.5 ...
 $ volatile.acidity    : num  0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.5 ...
 $ citric.acid         : num  0 0 0.04 0.56 0 0 0.06 0 0.02 0.36 ...
 $ residual.sugar      : num  1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 6.1 ...
 $ chlorides           : num  0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.071 ...
 $ free.sulfur.dioxide : num  11 25 15 17 11 13 15 15 9 17 ...
 $ total.sulfur.dioxide: num  34 67 54 60 34 40 59 21 18 102 ...
 $ density             : num  0.998 0.997 0.997 0.998 0.998 ...
 $ pH                  : num  3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.35 ...
 $ sulphates           : num  0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.8 ...
 $ alcohol             : num  9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 10.5 ...
 $ quality             : int  5 5 5 6 5 5 5 7 7 5 ...
       X          fixed.acidity   volatile.acidity  citric.acid   
 Min.   :   1.0   Min.   : 4.60   Min.   :0.1200   Min.   :0.000  
 1st Qu.: 400.5   1st Qu.: 7.10   1st Qu.:0.3900   1st Qu.:0.090  
 Median : 800.0   Median : 7.90   Median :0.5200   Median :0.260  
 Mean   : 800.0   Mean   : 8.32   Mean   :0.5278   Mean   :0.271  
 3rd Qu.:1199.5   3rd Qu.: 9.20   3rd Qu.:0.6400   3rd Qu.:0.420  
 Max.   :1599.0   Max.   :15.90   Max.   :1.5800   Max.   :1.000  
 residual.sugar     chlorides       free.sulfur.dioxide total.sulfur.dioxide
 Min.   : 0.900   Min.   :0.01200   Min.   : 1.00       Min.   :  6.00      
 1st Qu.: 1.900   1st Qu.:0.07000   1st Qu.: 7.00       1st Qu.: 22.00      
 Median : 2.200   Median :0.07900   Median :14.00       Median : 38.00      
 Mean   : 2.539   Mean   :0.08747   Mean   :15.87       Mean   : 46.47      
 3rd Qu.: 2.600   3rd Qu.:0.09000   3rd Qu.:21.00       3rd Qu.: 62.00      
 Max.   :15.500   Max.   :0.61100   Max.   :72.00       Max.   :289.00      
    density             pH          sulphates         alcohol     
 Min.   :0.9901   Min.   :2.740   Min.   :0.3300   Min.   : 8.40  
 1st Qu.:0.9956   1st Qu.:3.210   1st Qu.:0.5500   1st Qu.: 9.50  
 Median :0.9968   Median :3.310   Median :0.6200   Median :10.20  
 Mean   :0.9967   Mean   :3.311   Mean   :0.6581   Mean   :10.42  
 3rd Qu.:0.9978   3rd Qu.:3.400   3rd Qu.:0.7300   3rd Qu.:11.10  
 Max.   :1.0037   Max.   :4.010   Max.   :2.0000   Max.   :14.90  
    quality     
 Min.   :3.000  
 1st Qu.:5.000  
 Median :6.000  
 Mean   :5.636  
 3rd Qu.:6.000  
 Max.   :8.000  

What should the focus be?

Based on the summary statistics for the dataset, it would be interesting to explore what factors influence the quality of any given wine. The max quality for the wine is 8, minimum is 3 and the median is greater than the mean – 6.000 and 5.636 respectively.

 [1] "X"                    "fixed.acidity"        "volatile.acidity"    
 [4] "citric.acid"          "residual.sugar"       "chlorides"           
 [7] "free.sulfur.dioxide"  "total.sulfur.dioxide" "density"             
[10] "pH"                   "sulphates"            "alcohol"             
[13] "quality"             
 num [1:1599] 3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.35 ...
 num [1:1599] 1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 6.1 ...
 num [1:1599] 9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 10.5 ...
 int [1:1599] 5 5 5 6 5 5 5 7 7 5 ...
 num [1:1599] 7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 7.5 ...
 num [1:1599] 0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.5 ...

Inspect the histograms of variables of interest

I would like to explore the relationship between the quality of wine and the following:
1. residual sugar
2. pH
3. alcohol content
4. fixed acidity
5. volatile acidity

Due to the skew observable in the volatile acidity, fixed acidity, residual sugar, and alcohol variables, I wanted to log transform the scale to see if that would provide more insites into the distribution.

As the result of the transformation, the distributions appear to follow a more normal pattern.

   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    5.0     5.5     6.0     6.0     6.5     7.0 

Taking another look at the distribution of quality in the dataset we’re working with.

Let’s now try to explore the correlations between the quality of the wine we have subset and other features.

Indepth variable exploration

From the correlation plot we can see which features correlated with red wine quality. It appears that acidity and alcohol are significant ones.

Folowing the general boxplots above, let’s further explore the effect alcohol content has on the quality score of wine.

   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   8.40    9.50   10.20   10.42   11.10   14.90 
`show_guide` has been deprecated. Please use `show.legend` instead.

Seems from the box plot that the boxes move “up” as quality scores increase. This is indicative of a positive relationship between the two variables.

What other ways can we explore this trend?

What about the impact sugar has on wine quality score? I will repeat the same analysis for it as I did above for the residual sugar variable.

It does’t seem that better quality wines have more sugar than lower quality ones.

Let’s compare that with a few other features to be certain.

What about the correlation of acidity and pH observed in the plot?

It appears that acidity has a negative influence on a wine’s quality score. Let’s dive a little deeper.

Finding from this preliminary EDA:

Quality of red wine increases with increase in Alcohol content. Quality of red wine increases with decrease in acidity, in other words the higher the acidity the lower the quality of the wine.

Similarly, the quality of red wine suffers with increases in pH value. This makes sense considering the relationship between acidity and pH.

Residual sugars are not a good indicator of the quality of wine. Let’s explore that in a few different ways.

A final look at pH and Alcohol:

Final Plots and Summary

This section will include a recap of the three features I believe are important to consider when exploring the underlaying factors of what makes a red wine “good.” Those features are alcohol content, residual sugar, and volatile acidity of a wine.

Analysis of Volatile Acidity vs. Quality Score

To capture the negative effect of acidity on the quality of wine, we can revisit this plot:

We can see a decrease in quality with increase in volatile acidity. To make the chart easier to interpret, I have applied a log transformation to the volatile acidity variable. I think it is important to emphasize that volatile acidity alone is not a good indicator of the quality mark a particular wine might receive. It is actually fairly normally distributed and while we can say that having too much acidity is not good, it is hard to determine if there is a cut off point at which this dip in quality score occurs.

Analysis of Residual Sugar vs. Quality Score

In my opinon, the best illustration of the lack of significant effect of sugar on wine quality is the following plot.

As we can see, it is not possible to make a strong prediction as to what the wine quality may be based on the sugar content on a given wine. The sugar levels are scattered across different quality scores, which makes sense if you bring the data into the real world. There are many different types of “quality” wines - ranging from sweeter to less so. Yet again, sugar is not an indicator of what score a panel might give to a particular wine.

Analysis of Alcohol vs. Quality Score

Per my analysis, alcohol is quite a good indicator of the quality of wine as there is a positive correlation between alcohol content and the qulity score. This relationship can be visualized in a scatter plot with a line fit. The fitted line is exibits a positive slope as we move to higher wine ratings.

Indeed, alcohol has the strongest correlation found between a feature of wine and it’s quality. While the correlation is undenyable it is difficult to say if we can safely assume it is strong predictor in the quality of wine. I believe more analysis is necessary to make such a claim. Chances are that, while alcohol is a strong predictive feature, it is the combination of it and other chemical properties that result in the higher quality score.

Reflection:

There are many factors that influence the quality of wine and not all of them have been captured in this particular dataset. For instance, the aroma (bouquet) of a good wine is diffcult to analyze here. Nontheless, it is possible to find chemical features that can be used as quality predictors.

As this was my first project in R without a tutorial to follow, getting through certain parts presented a bit of a challenge. I had a plan to kick my analysis off with a correlation plot, however getting it to work properly took me quite a bit of time. I did in the process learn a lot more about the various types of correlation plots possible in R (‘cirle’,‘lower’, etc.). I do not think that my correlation plot is quite as good as I would like it to be. I would like to understand scaling a bit better and adjust the size of the output graphic to match my data better.

I did learn quite a bit, not only about using R but about red wine as well. I saw that there is also a similar dataset available for white wine, and in the future I would be interested in comparing the two datasets together. It would be interesting to see if quality of wineis related to the same features in red and white wine.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgojIyBQcm9qZWN0IG9iamVjdGl2ZTogClVzZSBSIGFuZCBhcHBseSBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIHRlY2huaXF1ZXMgdG8gZXhwbG9yZSByZWxhdGlvbnNoaXBzIGluIG9uZSB2YXJpYWJsZSB0byBtdWx0aXBsZSB2YXJpYWJsZXMgYW5kIHRvIGV4cGxvcmUgYSBzZWxlY3RlZCBkYXRhIHNldCBmb3IgZGlzdHJpYnV0aW9ucywgb3V0bGllcnMsIGFuZCBhbm9tYWxpZXMuCkkgd2lsbCBiZSB1c2luZyBhIFVkYWNpdHkgcmVjb21tZW5kZWQgZGF0YSBzZXQuCgojIERhdGE6Ckkgd2lsbCB1c2UgdGhlIHN1Z2dlc3RlZCByZWQgd2luZSBkYXRhIHNldCB3aGljaCBjb250YWlucyAxNTk5IG9iZXJ2YXRpb25zIG9mIApkaWZmZXJlbnQgcmVkIHdpbmVzIGFuZCB0aGVpciB2YXJpb3VzIGNoZW1pY2FsIHByb3BlcnRpZXMuIAoKIyMgTXkgYXBwcm9jaDoKSSB3aWxsIHVzZSB0aGUgcmVkIHdpbmUgcXVhbGl0eSBkYXRhc2V0IHRvIGV4cGxvcmUgd2hpY2ggZmVhdHVyZXMgb2Ygd2luZSAKY2FuIGJlIGluZGljYXRpdmUgb2YgaXQncyBxdWFsaXR5IHJhdGluZy4gVGhlIHF1YWxpdHkgcmF0aW5nIGlzIGFuIGF2ZXJlZ2EgZnJvbSAKYSB0YXN0aW5nIHBhbmVsLgoKYGBge3IgZ2xvYmFsX29wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFKQoKI0FkZGluZyB0aGlzIGNvZGUgdG8gaGlkZSBvdXRwdXRzIHRoYXQgYXJlIGlycmVsZXZhbnQgdG8gdGhlIGFuYWx5c2lzIGxpa2UgCiMgd2FybmluZ3MgYW5kIG1vZHVsZSBub3RpZmljYXRpb25zIHdoaWNoIG1ha2UgdGhlIGZpbmFsIHJlcG9ydCBsZXNzIHJlYWRhYmxlLgpgYGAKCkxvYWRpbmcgbmVjZXNzYXJ5IGxpYnJhcmllczoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoIkdHYWxseSIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KHNjYWxlcykKYGBgCgpMb2FkIGluIHRoZSBkYXRhdHNldDoKYGBge3J9CndpbmU8LXJlYWQuY3N2KCd3aW5lUXVhbGl0eVJlZHMuY3N2JykKYGBgCgojIyBWYXJpYWJsZSBkZXNjcmlwdGlvbgoxLiBGaXhlZCBhY2lkaXR5OiBtb3N0IGFjaWRzIGludm9sdmVkIHdpdGggd2luZSBvciBmaXhlZCBvciBub252b2xhdGlsZSAoZG8gbm90IGV2YXBvcmF0ZSByZWFkaWx5KQoyLiBWb2xhdGlsZSBhY2lkaXR5OiB0aGUgYW1vdW50IG9mIGFjZXRpYyBhY2lkIGluIHdpbmUsIHdoaWNoIGF0IHRvbyBoaWdoIG9mIGxldmVscyBjYW4gbGVhZCB0byBhbiB1bnBsZWFzYW50LCB2aW5lZ2FyIHRhc3RlCjMuIENpdHJpYyBhY2lkOiBmb3VuZCBpbiBzbWFsbCBxdWFudGl0aWVzLCBjaXRyaWMgYWNpZCBjYW4gYWRkIOKAmGZyZXNobmVzc+KAmSBhbmQgZmxhdm9yIHRvIHdpbmVzCjQuIFJlc2lkdWFsIHN1Z2FyOiB0aGUgYW1vdW50IG9mIHN1Z2FyIHJlbWFpbmluZyBhZnRlciBmZXJtZW50YXRpb24gc3RvcHMsIGl04oCZcyByYXJlIHRvIGZpbmQgd2luZXMgd2l0aCBsZXNzIHRoYW4gMSBncmFtL2xpdGVyIGFuZCB3aW5lcyB3aXRoIGdyZWF0ZXIgdGhhbiA0NSBncmFtcy9saXRlciBhcmUgY29uc2lkZXJlZCBzd2VldAo1LiBDaGxvcmlkZXM6IHRoZSBhbW91bnQgb2Ygc2FsdCBpbiB0aGUgd2luZQo2LiBGcmVlIHN1bGZ1ciBkaW94aWRlOiB0aGUgZnJlZSBmb3JtIG9mIFNPMiBleGlzdHMgaW4gZXF1aWxpYnJpdW0gYmV0d2VlbiBtb2xlY3VsYXIgU08yIChhcyBhIGRpc3NvbHZlZCBnYXMpIGFuZCBiaXN1bGZpdGUgaW9uOyBpdCBwcmV2ZW50cyBtaWNyb2JpYWwgZ3Jvd3RoIGFuZCB0aGUgb3hpZGF0aW9uIG9mIHdpbmUKNy4gVG90YWwgc3VsZnVyIGRpb3hpZGU6IGFtb3VudCBvZiBmcmVlIGFuZCBib3VuZCBmb3JtcyBvZiBTMDI7IGluIGxvdyBjb25jZW50cmF0aW9ucywgU08yIGlzIG1vc3RseSB1bmRldGVjdGFibGUgaW4gd2luZSwgYnV0IGF0IGZyZWUgU08yIGNvbmNlbnRyYXRpb25zIG92ZXIgNTAgcHBtLCBTTzIgYmVjb21lcyBldmlkZW50IGluIHRoZSBub3NlIGFuZCB0YXN0ZSBvZiB3aW5lCjguIERlbnNpdHk6IHRoZSBkZW5zaXR5IG9mIHdhdGVyIGlzIGNsb3NlIHRvIHRoYXQgb2Ygd2F0ZXIgZGVwZW5kaW5nIG9uIHRoZSBwZXJjZW50IGFsY29ob2wgYW5kIHN1Z2FyIGNvbnRlbnQKOS4gcEg6IGRlc2NyaWJlcyBob3cgYWNpZGljIG9yIGJhc2ljIGEgd2luZSBpcyBvbiBhIHNjYWxlIGZyb20gMCAodmVyeSBhY2lkaWMpIHRvIDE0ICh2ZXJ5IGJhc2ljKTsgbW9zdCB3aW5lcyBhcmUgYmV0d2VlbiAzLTQgb24gdGhlIHBIIHNjYWxlCjEwLiBTdWxwaGF0ZXM6IGEgd2luZSBhZGRpdGl2ZSB3aGljaCBjYW4gY29udHJpYnV0ZSB0byBzdWxmdXIgZGlveGlkZSBnYXMgKFMwMikgbGV2ZWxzLCB3aWNoIGFjdHMgYXMgYW4gYW50aW1pY3JvYmlhbCBhbmQgYW50aW94aWRhbnQKMTEuIEFsY29ob2w6IHRoZSBwZXJjZW50IGFsY29ob2wgY29udGVudCBvZiB0aGUgd2luZQoxMi4gUXVhbGl0eTogb3V0cHV0IHZhcmlhYmxlIChiYXNlZCBvbiBzZW5zb3J5IGRhdGEsIHNjb3JlIGJldHdlZW4gMCBhbmQgMTApCgoKCkxldCdzIGdldCBzb21lIHByZWxpbWluYXJ5IHN1bW1hcmllcyBvZiB0aGUgZGF0YToKCmBgYHtyfQpkaW0od2luZSkKCnN0cih3aW5lKQpzdW1tYXJ5KHdpbmUpCmBgYAoKIyMgV2hhdCBzaG91bGQgdGhlIGZvY3VzIGJlPwpCYXNlZCBvbiB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgZGF0YXNldCwgaXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gZXhwbG9yZSB3aGF0IGZhY3RvcnMgaW5mbHVlbmNlIHRoZSBxdWFsaXR5IG9mIGFueSBnaXZlbiB3aW5lLiAKVGhlIG1heCBxdWFsaXR5IGZvciB0aGUgd2luZSBpcyA4LCBtaW5pbXVtIGlzIDMgYW5kIHRoZSBtZWRpYW4gaXMgZ3JlYXRlciB0aGFuIHRoZSBtZWFuIC0tIDYuMDAwIGFuZCA1LjYzNiByZXNwZWN0aXZlbHkuCgpgYGB7cn0KbmFtZXMod2luZSkKYGBgCgoKYGBge3J9CnN0cih3aW5lJHBIKQpzdHIod2luZSRyZXNpZHVhbC5zdWdhcikKc3RyKHdpbmUkYWxjb2hvbCkKc3RyKHdpbmUkcXVhbGl0eSkKc3RyKHdpbmUkZml4ZWQuYWNpZGl0eSkKc3RyKHdpbmUkdm9sYXRpbGUuYWNpZGl0eSkKYGBgCgojIyBJbnNwZWN0IHRoZSBoaXN0b2dyYW1zIG9mIHZhcmlhYmxlcyBvZiBpbnRlcmVzdApJIHdvdWxkIGxpa2UgdG8gZXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHF1YWxpdHkgb2Ygd2luZSBhbmQgdGhlIGZvbGxvd2luZzogPGJyPgoxLiByZXNpZHVhbCBzdWdhciA8YnI+CjIuIHBIIDxicj4KMy4gYWxjb2hvbCBjb250ZW50IDxicj4KNC4gZml4ZWQgYWNpZGl0eSA8YnI+CjUuIHZvbGF0aWxlIGFjaWRpdHkgPGJyPgoKYGBge3J9CnFwbG90KHdpbmUkcXVhbGl0eSwgeGxhYiA9ICdXaW5lIFF1YWxpdHknKQpxcGxvdCh3aW5lJHJlc2lkdWFsLnN1Z2FyLCB4bGFiID0gJ1Jlc2lkdWFsIFN1Z2FyJykKcXBsb3Qod2luZSRwSCwgeGxhYiA9ICdwSCBsZXZlbCcpCnFwbG90KHdpbmUkYWxjb2hvbCwgeGxhYiA9ICdBbGNvaG9sJykKcXBsb3Qod2luZSRmaXhlZC5hY2lkaXR5LCB4bGFiID0gJ0ZpeGVkIEFjaWRpdHknKQpxcGxvdCh3aW5lJHZvbGF0aWxlLmFjaWRpdHksIHhsYWIgPSAnVm9sYXRpbGUgQWNpZGl0eScpCmBgYAoKRHVlIHRvIHRoZSBza2V3IG9ic2VydmFibGUgaW4gdGhlICoqdm9sYXRpbGUgYWNpZGl0eSoqLCAqKmZpeGVkIGFjaWRpdHkqKiwgKipyZXNpZHVhbCBzdWdhcioqLCBhbmQgKiphbGNvaG9sKiogdmFyaWFibGVzLCAKSSB3YW50ZWQgdG8gbG9nIHRyYW5zZm9ybSB0aGUgc2NhbGUgdG8gc2VlIGlmIHRoYXQgd291bGQgcHJvdmlkZSBtb3JlIGluc2l0ZXMgaW50byB0aGUgZGlzdHJpYnV0aW9uLgoKYGBge3J9CnJlc2lndWFsLnN1Z2FyX2xvZyA8LSBsb2cod2luZSRyZXNpZHVhbC5zdWdhcikKYWxjb2hvbF9sb2cgPC0gbG9nKHdpbmUkYWxjb2hvbCkKZml4ZWQuYWNpZGl0eV9sb2cgPC0gbG9nKHdpbmUkZml4ZWQuYWNpZGl0eSkKdm9sYXRpbGUuYWNpZGl0eV9sb2cgPC0gbG9nKHdpbmUkdm9sYXRpbGUuYWNpZGl0eSkKCnFwbG90KHJlc2lndWFsLnN1Z2FyX2xvZywgeGxhYiA9ICdSZXNpZHVhbCBTdWdhcicpCnFwbG90KGFsY29ob2xfbG9nLCB4bGFiID0gJ0FsY29ob2wnKQpxcGxvdChmaXhlZC5hY2lkaXR5X2xvZywgeGxhYiA9ICdGaXhlZCBBY2lkaXR5JykKcXBsb3Qodm9sYXRpbGUuYWNpZGl0eV9sb2csIHhsYWIgPSAnVm9sYXRpbGUgQWNpZGl0eScpCmBgYAoKQXMgdGhlIHJlc3VsdCBvZiB0aGUgdHJhbnNmb3JtYXRpb24sIHRoZSBkaXN0cmlidXRpb25zIGFwcGVhciB0byBmb2xsb3cgYSBtb3JlIG5vcm1hbCBwYXR0ZXJuLgoKYGBge3J9CnggPSBxdWFudGlsZSh3aW5lJHF1YWxpdHksIHByb2JzPWMoMC4wNSwgMC45NSkgKQpzdW1tYXJ5KHgpCmBgYAoKVGFraW5nIGFub3RoZXIgbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHF1YWxpdHkgaW4gdGhlIGRhdGFzZXQgd2UncmUgd29ya2luZyB3aXRoLiAKCmBgYHtyfQpnZ3Bsb3QoIGFlcyh4PSBxdWFsaXR5KSwgIGRhdGE9d2luZSApKwogIGdlb21fYmFyKCkKYGBgCgpgYGB7cn0Kd2luZV9xdWFsaXR5X2ZpbHRlcmVkID0gd2luZQp3aW5lJHF1YWxpdHlfc2NvcmU8LWN1dCh3aW5lX3F1YWxpdHlfZmlsdGVyZWQkcXVhbGl0eSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYygyLjUsMy41LDQuNSw1LjUsNi41LDcuNSw4LjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCczJywnNCcsJzUnLCc2JywnNycsJzgnKSkKYGBgCgpMZXQncyBub3cgdHJ5IHRvIGV4cGxvcmUgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZSBxdWFsaXR5IG9mIHRoZSB3aW5lIHdlCmhhdmUgc3Vic2V0IGFuZCBvdGhlciBmZWF0dXJlcy4KCmBgYHtyfQojaW1wb3J0IGNvcnJlbGF0aW9uIHBsb3QgCmluc3RhbGwucGFja2FnZXMoImNvcnJwbG90IikKbGlicmFyeShjb3JycGxvdCkKYGBgCgoKYGBge3J9CmdncCA9IGdncGFpcnMod2luZSkKcHJpbnQoZ2dwLCBwcm9ncmVzcyA9IEYpICAjIG5vIHByb2dyZXNzIGJhcgojcHJpbnQoZ2dwKSAKYGBgCgojIyBJbmRlcHRoIHZhcmlhYmxlIGV4cGxvcmF0aW9uCgpGcm9tIHRoZSBjb3JyZWxhdGlvbiBwbG90IHdlIGNhbiBzZWUgd2hpY2ggZmVhdHVyZXMgY29ycmVsYXRlZCB3aXRoIHJlZCB3aW5lIHF1YWxpdHkuCkl0IGFwcGVhcnMgdGhhdCAqKmFjaWRpdHkqKiBhbmQgKiphbGNvaG9sKiogYXJlIHNpZ25pZmljYW50IG9uZXMuCgpgYGB7cn0KZ3JpZC5hcnJhbmdlKAoKZ2dwbG90KGFlcyh4PXF1YWxpdHlfc2NvcmUsIHk9YWxjb2hvbCksZGF0YT13aW5lICkrCiAgICAgIGdlb21fYm94cGxvdCggKSwKCmdncGxvdChhZXMoeD1xdWFsaXR5X3Njb3JlLCB5PXZvbGF0aWxlLmFjaWRpdHkpLGRhdGE9d2luZSApKwogICAgICBnZW9tX2JveHBsb3QoICksCgpnZ3Bsb3QoYWVzKHg9cXVhbGl0eV9zY29yZSwgeT1maXhlZC5hY2lkaXR5KSxkYXRhPXdpbmUgKSsKICAgICAgZ2VvbV9ib3hwbG90KCApCgopCmBgYApgYGB7cn0KZ3JpZC5hcnJhbmdlKAoKZ2dwbG90KGFlcyh4PXF1YWxpdHksIHk9IGxvZyhmaXhlZC5hY2lkaXR5KSksZGF0YT13aW5lICkrCiAgICAgIGdlb21fcG9pbnQoYWxwaGE9MS81KSwKCmdncGxvdChhZXMoeD1xdWFsaXR5LCB5PSBsb2codm9sYXRpbGUuYWNpZGl0eSkpLGRhdGE9d2luZSApKwogICAgICBnZW9tX3BvaW50KGFscGhhPTEvNSkpCmBgYAoKCkZvbG93aW5nIHRoZSBnZW5lcmFsIGJveHBsb3RzIGFib3ZlLCBsZXQncyBmdXJ0aGVyIGV4cGxvcmUgdGhlIGVmZmVjdCBhbGNvaG9sIApjb250ZW50IGhhcyBvbiB0aGUgcXVhbGl0eSBzY29yZSBvZiB3aW5lLgoKYGBge3J9CnN1bW1hcnkod2luZSRhbGNvaG9sKQoKd2luZV9hbGNvaG9sX21lYW4gPC0gbWVhbih3aW5lJGFsY29ob2wpCndpbmVfYWxjb2hvbF9tZWRpYW4gPC0gbWVkaWFuKHdpbmUkYWxjb2hvbCkKd2luZV9xdWFsaXR5X21lYW4gPC0gbWVhbih3aW5lJHF1YWxpdHkpCndpbmVfcXVhbGl0eV9taW4gPC0gbWluKHdpbmUkcXVhbGl0eSkKd2luZV9xdWFsaXR5X21heCA8LSBtYXgod2luZSRxdWFsaXR5KQoKZ2dwbG90KGRhdGE9d2luZSwgYWVzKHg9cXVhbGl0eV9zY29yZSwgeT1hbGNvaG9sKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgZ2VvbV9obGluZShzaG93X2d1aWRlPVQsIHlpbnRlcmNlcHQ9d2luZV9hbGNvaG9sX21lYW4sIGxpbmV0eXBlPSdsb25nZGFzaCcsCiAgICAgICAgICAgICAgIGFscGhhPS41LCBjb2xvcj0nYmx1ZScpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHdpbmVfcXVhbGl0eV9tZWFuLXdpbmVfcXVhbGl0eV9taW4rMSwKICAgICAgICAgICAgICAgbGluZXR5cGU9J2xvbmdkYXNoJywgY29sb3I9J2JsdWUnLCBhbHBoYT0uNSkgKwogICAgeGxhYigiV2luZSBRdWFsaXR5IikgKwogICAgeWxhYigiQWxjb2hvbCIpCgoKYGBgCgpTZWVtcyBmcm9tIHRoZSBib3ggcGxvdCB0aGF0IHRoZSBib3hlcyBtb3ZlICJ1cCIgYXMgcXVhbGl0eSBzY29yZXMgaW5jcmVhc2UuIApUaGlzIGlzIGluZGljYXRpdmUgb2YgYSBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4KCldoYXQgb3RoZXIgd2F5cyBjYW4gd2UgZXhwbG9yZSB0aGlzIHRyZW5kPwoKYGBge3J9CiNBIHNjYXR0ZXIgcGxvdCB3aXRoIGEgc3RyYWlnaGxpbmUgZml0dGVyIHRocm91Z2ggbWF5IHNoZWQgc29tZSBtb3JlIGxpZ2h0IG9uIAojdGhpcyB0cmVuZC4KCmdncGxvdChkYXRhPXdpbmUsIGFlcyh4PWFzLm51bWVyaWMocXVhbGl0eSksIHk9YWxjb2hvbCkpICsKICAgIGdlb21faml0dGVyKGFscGhhPTEvMykgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScsIGFlcyhncm91cCA9IDEpKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdD13aW5lX2FsY29ob2xfbWVhbiwgbGluZXR5cGU9J2xvbmdkYXNoJywgYWxwaGE9LjUsCiAgICAgICAgICAgICAgIGNvbG9yPSdibHVlJykgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gd2luZV9xdWFsaXR5X21lYW4sIGxpbmV0eXBlPSdsb25nZGFzaCcsCiAgICAgICAgICAgICAgIGNvbG9yPSdibHVlJywgYWxwaGE9LjUpICsKICAgIHhsYWIoIldpbmUgUXVhbGl0eSIpICsKICAgIHlsYWIoIkFsY29ob2wiKQpgYGAKCldoYXQgYWJvdXQgdGhlIGltcGFjdCBzdWdhciBoYXMgb24gd2luZSBxdWFsaXR5IHNjb3JlPyBJIHdpbGwgcmVwZWF0IHRoZSBzYW1lIGFuYWx5c2lzIGZvciBpdCBhcyBJIGRpZCBhYm92ZSBmb3IgdGhlIHJlc2lkdWFsIHN1Z2FyIHZhcmlhYmxlLgoKYGBge3J9CndpbmVfc3VnYXJfbWVhbiA8LSBtZWFuKHdpbmUkY2l0cmljLmFjaWQpCndpbmVfc3VnYXJfbWVkaWFuIDwtIG1lZGlhbih3aW5lJGNpdHJpYy5hY2lkKQp3aW5lX3N1Z2FyX3NkIDwtIHNkKHdpbmUkY2l0cmljLmFjaWQpCndpbmVfc3VnYXJfbWF4IDwtIG1heCh3aW5lJGNpdHJpYy5hY2lkKQpgYGAKYGBge3J9CmdncGxvdChkYXRhPXdpbmUsIGFlcyh4PXF1YWxpdHlfc2NvcmUsIHk9cmVzaWR1YWwuc3VnYXIpKSArCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICBnZW9tX2hsaW5lKHNob3cubGVnZW5kPVQsIHlpbnRlcmNlcHQ9d2luZV9zdWdhcl9tZWFuLCBsaW5ldHlwZT0nbG9uZ2Rhc2gnLAogICAgICAgICAgICAgICBhbHBoYT0uNSwgY29sb3I9J2JsdWUnKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSB3aW5lX3F1YWxpdHlfbWVhbi13aW5lX3F1YWxpdHlfbWluKzEsIGxpbmV0eXBlPSdsb25nZGFzaCcsCiAgICAgICAgICAgICAgIGNvbG9yPSdibHVlJywgYWxwaGE9LjUpICsKICAgIHhsYWIoIldpbmUgUXVhbGl0eSIpICsKICAgIHlsYWIoIlJlc2lkdWFsIFN1Z2FyIikKYGBgCmBgYHtyfQpnZ3Bsb3QoZGF0YT13aW5lLCBhZXMoeD1hcy5udW1lcmljKHF1YWxpdHlfc2NvcmUpLCB5PXJlc2lkdWFsLnN1Z2FyKSkgKwogICAgZ2VvbV9qaXR0ZXIoYWxwaGE9MS8zKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJywgYWVzKGdyb3VwID0gMSkpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PXdpbmVfc3VnYXJfbWVhbiwgbGluZXR5cGU9J2xvbmdkYXNoJywgYWxwaGE9LjUsCiAgICAgICAgICAgICAgIGNvbG9yPSdibHVlJykgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gd2luZV9xdWFsaXR5X21lYW4sIGxpbmV0eXBlPSdsb25nZGFzaCcsIGFscGhhPS41LCAKICAgICAgICAgICAgICAgY29sb3I9J2JsdWUnKSArCiAgICB4bGFiKCJXaW5lIFF1YWxpdHkiKSArCiAgICB5bGFiKCJSZXNpZHVhbCBTdWdhciIpCmBgYAoKSXQgZG9lcyd0IHNlZW0gdGhhdCBiZXR0ZXIgcXVhbGl0eSB3aW5lcyBoYXZlIG1vcmUgc3VnYXIgdGhhbiBsb3dlciBxdWFsaXR5IG9uZXMuIAoKTGV0J3MgY29tcGFyZSB0aGF0IHdpdGggYSBmZXcgb3RoZXIgZmVhdHVyZXMgdG8gYmUgY2VydGFpbi4KCmBgYHtyfQpncmlkLmFycmFuZ2UoCmdncGxvdChhZXMoeD1xdWFsaXR5X3Njb3JlLCB5PXBIKSxkYXRhPXdpbmUgKSsKICAgICAgZ2VvbV9ib3hwbG90KCApLAoKI1Bsb3QgYm90aCB0aGUgcmVndWxhciBwSCBhbmQgb25lIG9uIGEgbW9yZSBmaW5lIHktc2NhbGUuCgpnZ3Bsb3QoYWVzKHg9cXVhbGl0eV9zY29yZSwgeT1wSCksZGF0YT13aW5lICkrCiAgICAgIGdlb21fYm94cGxvdCggKSsKICAgICAgY29vcmRfdHJhbnMoeT0gJ2xvZzEwJykpCmBgYAoKV2hhdCBhYm91dCB0aGUgY29ycmVsYXRpb24gb2YgYWNpZGl0eSBhbmQgcEggb2JzZXJ2ZWQgaW4gdGhlIHBsb3Q/CgpgYGB7cn0KZ3JpZC5hcnJhbmdlKAoKZ2dwbG90KGFlcyh4PXBILCB5PWZpeGVkLmFjaWRpdHkpLGRhdGE9d2luZSApKwogICAgICBnZW9tX3BvaW50KGFscGhhPTEvNSksCgpnZ3Bsb3QoYWVzKHg9cEgsIHk9dm9sYXRpbGUuYWNpZGl0eSksZGF0YT13aW5lKSsKICAgICAgZ2VvbV9wb2ludChhbHBoYT0xLzUpLAoKZ2dwbG90KGFlcyh4PXBILCB5PWNpdHJpYy5hY2lkKSxkYXRhPXdpbmUpKwogICAgICBnZW9tX3BvaW50KGFscGhhPTEvNSkpCmBgYAoKSXQgYXBwZWFycyB0aGF0IGFjaWRpdHkgaGFzIGEgbmVnYXRpdmUgaW5mbHVlbmNlIG9uIGEgd2luZeKAmXMgcXVhbGl0eSBzY29yZS4KTGV0J3MgZGl2ZSBhIGxpdHRsZSBkZWVwZXIuCgpgYGB7cn0KZ2dwbG90KGFlcyh4ID0gZml4ZWQuYWNpZGl0eSwgeSA9IHZvbGF0aWxlLmFjaWRpdHksIHF1YWxpdHkgPSBxdWFsaXR5KSwgZGF0YSA9IHdpbmUpICsKICAgIGZhY2V0X3dyYXAofnF1YWxpdHkpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAzLCBhbHBoYSA9IDEvNCkgKwogICAgc2NhbGVfY29sb3JfaWRlbnRpdHkoZ3VpZGUgPSAnbGVnZW5kJykgKwogICAgeWxpbShtaW4od2luZSR2b2xhdGlsZS5hY2lkaXR5KSwgcXVhbnRpbGUod2luZSR2b2xhdGlsZS5hY2lkaXR5LCAwLjk1KSkgKwogICAgeGxpbShtaW4od2luZSRmaXhlZC5hY2lkaXR5KSwgcXVhbnRpbGUod2luZSRmaXhlZC5hY2lkaXR5LCAwLjk1KSkgCmBgYAoKIyMgRmluZGluZyBmcm9tIHRoaXMgcHJlbGltaW5hcnkgRURBOgpRdWFsaXR5IG9mIHJlZCB3aW5lIGluY3JlYXNlcyB3aXRoIGluY3JlYXNlIGluIEFsY29ob2wgY29udGVudC4KUXVhbGl0eSBvZiByZWQgd2luZSBpbmNyZWFzZXMgd2l0aCBkZWNyZWFzZSBpbiBhY2lkaXR5LCAKaW4gb3RoZXIgd29yZHMgdGhlIGhpZ2hlciB0aGUgYWNpZGl0eSB0aGUgbG93ZXIgdGhlIHF1YWxpdHkgb2YgdGhlIHdpbmUuCgpTaW1pbGFybHksIHRoZSBxdWFsaXR5IG9mIHJlZCB3aW5lIHN1ZmZlcnMgd2l0aCBpbmNyZWFzZXMgaW4gcEggdmFsdWUuIApUaGlzIG1ha2VzIHNlbnNlIGNvbnNpZGVyaW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhY2lkaXR5IGFuZCBwSC4KClJlc2lkdWFsIHN1Z2FycyBhcmUgbm90IGEgZ29vZCBpbmRpY2F0b3Igb2YgdGhlIHF1YWxpdHkgb2Ygd2luZS4KTGV0J3MgZXhwbG9yZSB0aGF0IGluIGEgZmV3IGRpZmZlcmVudCB3YXlzLgoKYGBge3J9CiBmIDwtIGZ1bmN0aW9uKGRhdGFzZXQsIHgsIHksIHosIG9wdHM9TlVMTCkgewogIGdncGxvdChkYXRhc2V0LCBhZXNfc3RyaW5nKHggPSB4LCB5ID0geSwgY29sb3IgPSB6KSkgKwogICBnZW9tX3BvaW50KGFscGhhID0gMS81LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcihoID0gMCksIHNpemUgPSAyKSArCiAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpCiAgIH0KCnAgPC0gZih3aW5lLCAicmVzaWR1YWwuc3VnYXIiLCAiYWxjb2hvbCIsIGZhY3RvcigicXVhbGl0eSIpKQoKIyBVc2luZyBkaWZmZXJlbnQgd2F5cyBvZiBleGFtaW5pbmcgdGhlIHNjYXR0ZXIKcCArIGNvb3JkX2NhcnRlc2lhbih4bGltPWMobWluKHdpbmUkcmVzaWR1YWwuc3VnYXIpLDIwKSwgCiAgICAgICAgICAgICAgICAgICAgeWxpbT1jKG1pbih3aW5lJGFsY29ob2wpLCAxNSkpICsgdGhlbWVfZGFyaygpCgooZCA8LSBnZ3Bsb3Qod2luZSwgYWVzKHF1YWxpdHlfc2NvcmUsIHJlc2lkdWFsLnN1Z2FyKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcXVhbGl0eV9zY29yZSkpKQoKCmBgYApgYGB7cn0KZCArIHNjYWxlX2NvbG91cl9icmV3ZXIoIldpbmUkcXVhbGl0eV9zY29yZSIpICsgdGhlbWVfZGFyaygpCmBgYAoKQSBmaW5hbCBsb29rIGF0IHBIIGFuZCBBbGNvaG9sOgoKYGBge3J9CmdncGxvdChhZXMoeCA9IHBILCB5ID0gYWxjb2hvbCwgcXVhbGl0eSA9IHF1YWxpdHkpLCBkYXRhID0gd2luZSkgKwogICAgZmFjZXRfd3JhcCh+cXVhbGl0eSkgKyAKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMS80KSArCiAgICBzY2FsZV9jb2xvcl9pZGVudGl0eShndWlkZSA9ICdsZWdlbmQnKSArCiAgICB5bGltKG1pbih3aW5lJGFsY29ob2wpLCBxdWFudGlsZSh3aW5lJGFsY29ob2wsIDAuOTUpKSArCiAgICB4bGltKG1pbih3aW5lJHBIKSwgcXVhbnRpbGUod2luZSRwSCwgMC45NSkpIApgYGAKCiMjIEZpbmFsIFBsb3RzIGFuZCBTdW1tYXJ5ClRoaXMgc2VjdGlvbiB3aWxsIGluY2x1ZGUgYSByZWNhcCBvZiB0aGUgdGhyZWUgZmVhdHVyZXMgSSBiZWxpZXZlIGFyZSBpbXBvcnRhbnQgdG8gY29uc2lkZXIKd2hlbiBleHBsb3JpbmcgdGhlIHVuZGVybGF5aW5nIGZhY3RvcnMgb2Ygd2hhdCBtYWtlcyBhIHJlZCB3aW5lICJnb29kLiIgVGhvc2UgZmVhdHVyZXMgYXJlCmFsY29ob2wgY29udGVudCwgcmVzaWR1YWwgc3VnYXIsIGFuZCB2b2xhdGlsZSBhY2lkaXR5IG9mIGEgd2luZS4gCgojIyNBbmFseXNpcyBvZiBWb2xhdGlsZSBBY2lkaXR5IHZzLiBRdWFsaXR5IFNjb3JlClRvIGNhcHR1cmUgdGhlIG5lZ2F0aXZlIGVmZmVjdCBvZiBhY2lkaXR5IG9uIHRoZSBxdWFsaXR5IG9mIHdpbmUsIHdlIGNhbiByZXZpc2l0CnRoaXMgcGxvdDoKYGBge3J9CmdncGxvdChhZXMoeD1xdWFsaXR5X3Njb3JlLCB5PSBsb2codm9sYXRpbGUuYWNpZGl0eSkpLGRhdGE9d2luZSApKwogICAgICBnZW9tX2JveHBsb3QoICkgKwogICAgICBnZ3RpdGxlKCJWb2xhdGlsZSBBY2lkaXR5IFNwcmVhZCBpbiBXaW5lIikKYGBgCgpXZSBjYW4gc2VlIGEgZGVjcmVhc2UgaW4gcXVhbGl0eSB3aXRoIGluY3JlYXNlIGluIHZvbGF0aWxlIGFjaWRpdHkuClRvIG1ha2UgdGhlIGNoYXJ0IGVhc2llciB0byBpbnRlcnByZXQsIEkgaGF2ZSBhcHBsaWVkIGEgbG9nIHRyYW5zZm9ybWF0aW9uIHRvIHRoZQp2b2xhdGlsZSBhY2lkaXR5IHZhcmlhYmxlLiAKSSB0aGluayBpdCBpcyBpbXBvcnRhbnQgdG8gZW1waGFzaXplIHRoYXQgdm9sYXRpbGUgYWNpZGl0eSBhbG9uZSBpcyBub3QgYSBnb29kIGluZGljYXRvciAKb2YgdGhlIHF1YWxpdHkgbWFyayBhIHBhcnRpY3VsYXIgd2luZSBtaWdodCByZWNlaXZlLiBJdCBpcyBhY3R1YWxseSBmYWlybHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQKYW5kIHdoaWxlIHdlIGNhbiBzYXkgdGhhdCBoYXZpbmcgdG9vIG11Y2ggYWNpZGl0eSBpcyBub3QgZ29vZCwgaXQgaXMgaGFyZCB0byBkZXRlcm1pbmUgCmlmIHRoZXJlIGlzIGEgY3V0IG9mZiBwb2ludCBhdCB3aGljaCB0aGlzIGRpcCBpbiBxdWFsaXR5IHNjb3JlIG9jY3Vycy4KCiMjI0FuYWx5c2lzIG9mIFJlc2lkdWFsIFN1Z2FyIHZzLiBRdWFsaXR5IFNjb3JlCkluIG15IG9waW5vbiwgdGhlIGJlc3QgaWxsdXN0cmF0aW9uIG9mIHRoZSBsYWNrIG9mIHNpZ25pZmljYW50IGVmZmVjdCBvZiBzdWdhciBvbiAKd2luZSBxdWFsaXR5IGlzIHRoZSBmb2xsb3dpbmcgcGxvdC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YT13aW5lLCBhZXMoeD1hcy5udW1lcmljKHF1YWxpdHlfc2NvcmUpLCB5PXJlc2lkdWFsLnN1Z2FyKSkgKwogICAgZ2VvbV9qaXR0ZXIoYWxwaGE9MS8zKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJywgYWVzKGdyb3VwID0gMSkpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PXdpbmVfc3VnYXJfbWVhbiwgbGluZXR5cGU9J2xvbmdkYXNoJywgYWxwaGE9LjUsCiAgICAgICAgICAgICAgIGNvbG9yPSdibHVlJykgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gd2luZV9xdWFsaXR5X21lYW4sIGxpbmV0eXBlPSdsb25nZGFzaCcsIGFscGhhPS41LCAKICAgICAgICAgICAgICAgY29sb3I9J2JsdWUnKSArCiAgICBnZ3RpdGxlKCJTdWdhciBDb250ZW50IHZzLiBXaW5lIFF1YWxpdHkiKSArCiAgICB4bGFiKCJXaW5lIFF1YWxpdHkiKSArCiAgICB5bGFiKCJSZXNpZHVhbCBTdWdhciAoZy9kbV4zKSIpCmBgYAoKQXMgd2UgY2FuIHNlZSwgaXQgaXMgbm90IHBvc3NpYmxlIHRvIG1ha2UgYSBzdHJvbmcgcHJlZGljdGlvbiBhcyB0byB3aGF0IHRoZSB3aW5lIHF1YWxpdHkgCm1heSBiZSBiYXNlZCBvbiB0aGUgc3VnYXIgY29udGVudCBvbiBhIGdpdmVuIHdpbmUuIFRoZSBzdWdhciBsZXZlbHMgYXJlIHNjYXR0ZXJlZCBhY3Jvc3MgZGlmZmVyZW50CnF1YWxpdHkgc2NvcmVzLCB3aGljaCBtYWtlcyBzZW5zZSBpZiB5b3UgYnJpbmcgdGhlIGRhdGEgaW50byB0aGUgcmVhbCB3b3JsZC4KVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IHR5cGVzIG9mICJxdWFsaXR5IiB3aW5lcyAtIHJhbmdpbmcgZnJvbSBzd2VldGVyIHRvIGxlc3Mgc28uIApZZXQgYWdhaW4sIHN1Z2FyIGlzIG5vdCBhbiBpbmRpY2F0b3Igb2Ygd2hhdCBzY29yZSBhIHBhbmVsIG1pZ2h0IGdpdmUgdG8gYSBwYXJ0aWN1bGFyIAp3aW5lLgoKIyMjIEFuYWx5c2lzIG9mIEFsY29ob2wgdnMuIFF1YWxpdHkgU2NvcmUKUGVyIG15IGFuYWx5c2lzLCBhbGNvaG9sIGlzIHF1aXRlIGEgZ29vZCBpbmRpY2F0b3Igb2YgdGhlIHF1YWxpdHkgb2Ygd2luZQphcyB0aGVyZSBpcyBhIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gYWxjb2hvbCBjb250ZW50IGFuZCB0aGUgcXVsaXR5IHNjb3JlLiAKVGhpcyByZWxhdGlvbnNoaXAgY2FuIGJlIHZpc3VhbGl6ZWQgaW4gYSBzY2F0dGVyIHBsb3Qgd2l0aCBhIGxpbmUgZml0LgpUaGUgZml0dGVkIGxpbmUgaXMgZXhpYml0cyBhIHBvc2l0aXZlIHNsb3BlIGFzIHdlIG1vdmUgdG8gaGlnaGVyIHdpbmUgcmF0aW5ncy4KCmBgYHtyfQoKZ2dwbG90KGRhdGE9d2luZSwgYWVzKHg9YXMubnVtZXJpYyhxdWFsaXR5KSwgeT1hbGNvaG9sKSkgKwogICAgZ2VvbV9qaXR0ZXIoYWxwaGE9MS8zKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJywgYWVzKGdyb3VwID0gMSkpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PXdpbmVfYWxjb2hvbF9tZWFuLCBsaW5ldHlwZT0nbG9uZ2Rhc2gnLCBhbHBoYT0uNSwKICAgICAgICAgICAgICAgY29sb3I9J2JsdWUnKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSB3aW5lX3F1YWxpdHlfbWVhbiwgbGluZXR5cGU9J2xvbmdkYXNoJywKICAgICAgICAgICAgICAgY29sb3I9J2JsdWUnLCBhbHBoYT0uNSkgKwogICAgZ2d0aXRsZSgiQWxjb2hvbCAlIHZzLiBXaW5lIFF1YWxpdHkiKSArCiAgICB4bGFiKCJXaW5lIFF1YWxpdHkiKSArCiAgICB5bGFiKCJBbGNvaG9sICglKSIpCmBgYAoKSW5kZWVkLCBhbGNvaG9sIGhhcyB0aGUgc3Ryb25nZXN0IGNvcnJlbGF0aW9uIGZvdW5kIGJldHdlZW4gYSBmZWF0dXJlIG9mIHdpbmUgCmFuZCBpdCdzIHF1YWxpdHkuCldoaWxlIHRoZSBjb3JyZWxhdGlvbiBpcyB1bmRlbnlhYmxlIGl0IGlzIGRpZmZpY3VsdCB0byBzYXkgaWYgd2UgY2FuIHNhZmVseSBhc3N1bWUgaXQgaXMgCnN0cm9uZyBwcmVkaWN0b3IgaW4gdGhlIHF1YWxpdHkgb2Ygd2luZS4gSSBiZWxpZXZlIG1vcmUgYW5hbHlzaXMgaXMgbmVjZXNzYXJ5IHRvIG1ha2Ugc3VjaCBhIGNsYWltLgpDaGFuY2VzIGFyZSB0aGF0LCB3aGlsZSBhbGNvaG9sIGlzIGEgc3Ryb25nIHByZWRpY3RpdmUgZmVhdHVyZSwgaXQgaXMgdGhlIGNvbWJpbmF0aW9uIG9mIGl0IGFuZCBvdGhlciBjaGVtaWNhbApwcm9wZXJ0aWVzIHRoYXQgcmVzdWx0IGluIHRoZSBoaWdoZXIgcXVhbGl0eSBzY29yZS4KCiMjIFJlZmxlY3Rpb246ClRoZXJlIGFyZSBtYW55IGZhY3RvcnMgdGhhdCBpbmZsdWVuY2UgdGhlIHF1YWxpdHkgb2Ygd2luZSBhbmQgbm90IGFsbCBvZiB0aGVtIApoYXZlIGJlZW4gY2FwdHVyZWQgaW4gdGhpcyBwYXJ0aWN1bGFyIGRhdGFzZXQuIEZvciBpbnN0YW5jZSwgdGhlIGFyb21hIChib3VxdWV0KQpvZiBhIGdvb2Qgd2luZSBpcyBkaWZmY3VsdCB0byBhbmFseXplIGhlcmUuIE5vbnRoZWxlc3MsIGl0IGlzIHBvc3NpYmxlIHRvIGZpbmQgCmNoZW1pY2FsIGZlYXR1cmVzIHRoYXQgY2FuIGJlIHVzZWQgYXMgcXVhbGl0eSBwcmVkaWN0b3JzLgoKQXMgdGhpcyB3YXMgbXkgZmlyc3QgcHJvamVjdCBpbiBSIHdpdGhvdXQgYSB0dXRvcmlhbCB0byBmb2xsb3csIGdldHRpbmcgdGhyb3VnaCAKY2VydGFpbiBwYXJ0cyBwcmVzZW50ZWQgYSBiaXQgb2YgYSBjaGFsbGVuZ2UuIEkgaGFkIGEgcGxhbiB0byBraWNrIG15IGFuYWx5c2lzIApvZmYgd2l0aCBhIGNvcnJlbGF0aW9uIHBsb3QsIGhvd2V2ZXIgZ2V0dGluZyBpdCB0byB3b3JrIHByb3Blcmx5IHRvb2sgbWUgcXVpdGUgCmEgYml0IG9mIHRpbWUuIEkgZGlkIGluIHRoZSBwcm9jZXNzIGxlYXJuIGEgbG90IG1vcmUgYWJvdXQgdGhlIHZhcmlvdXMgdHlwZXMgb2YgCmNvcnJlbGF0aW9uIHBsb3RzIHBvc3NpYmxlIGluIFIgKCdjaXJsZScsJ2xvd2VyJywgZXRjLikuCkkgZG8gbm90IHRoaW5rIHRoYXQgbXkgY29ycmVsYXRpb24gcGxvdCBpcyBxdWl0ZSBhcyBnb29kIGFzIEkgd291bGQgbGlrZSBpdCB0byBiZS4gCkkgd291bGQgbGlrZSB0byB1bmRlcnN0YW5kIHNjYWxpbmcgYSBiaXQgYmV0dGVyIGFuZCBhZGp1c3QgdGhlIHNpemUgb2YgdGhlIG91dHB1dCAKZ3JhcGhpYyB0byBtYXRjaCBteSBkYXRhIGJldHRlci4gCgpJIGRpZCBsZWFybiBxdWl0ZSBhIGJpdCwgbm90IG9ubHkgYWJvdXQgdXNpbmcgUiBidXQgYWJvdXQgcmVkIHdpbmUgYXMgd2VsbC4gCkkgc2F3IHRoYXQgdGhlcmUgaXMgYWxzbyBhIHNpbWlsYXIgZGF0YXNldCBhdmFpbGFibGUgZm9yIHdoaXRlIHdpbmUsIGFuZCBpbiB0aGUgCmZ1dHVyZSBJIHdvdWxkIGJlIGludGVyZXN0ZWQgaW4gY29tcGFyaW5nIHRoZSB0d28gZGF0YXNldHMgdG9nZXRoZXIuIEl0IHdvdWxkIGJlIAppbnRlcmVzdGluZyB0byBzZWUgaWYgcXVhbGl0eSBvZiB3aW5laXMgcmVsYXRlZCB0byB0aGUgc2FtZSBmZWF0dXJlcyBpbiByZWQgYW5kIHdoaXRlIHdpbmUuCgoKIyMgUmVmZXJlbmNlczoKaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vcGxvdC1tYXRyaXgtd2l0aC10aGUtci1wYWNrYWdlLWdnYWxseS8KaHR0cDovL2dhbGxlcnkuci1lbnRodXNpYXN0cy5jb20vUkdyYXBoR2FsbGVyeS5waHA/Z3JhcGg9MTM3Cmh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9jb3JycGxvdC92aWduZXR0ZXMvY29ycnBsb3QtaW50cm8uaHRtbGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vdWNpbWwvcmVkLXdpbmUtcXVhbGl0eS1jb3J0ZXotZXQtYWwtMjAwOQoKIyMgRGF0YXNldDoKaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS91cmw/cT1odHRwczovL3MzLmFtYXpvbmF3cy5jb20vdWRhY2l0eS1ob3N0ZWQtZG93bmxvYWRzL3VkNjUxL3dpbmVRdWFsaXR5UmVkcy5jc3Ymc2E9RCZ1c3Q9MTUyNTgwNTIyOTE5NjAwMAo=